package longshu.srpc.client.impl;

import lombok.extern.slf4j.Slf4j;
import longshu.srpc.IOUtils;
import longshu.srpc.api.RpcProtocol;
import longshu.srpc.api.RpcRequest;
import longshu.srpc.api.RpcResponse;
import longshu.srpc.client.RpcConnector;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.Socket;
import java.net.URL;

/**
 * SimpleRpcConnector
 *
 * @author LongShu 2017/12/03
 */
@Slf4j
public class SimpleRpcConnector implements RpcConnector {

    private String protocol;
    private String host;
    private int port;
    private String serverAddress;

    private RpcProtocol rpcProtocol;

    public SimpleRpcConnector(String serverAddress) {
        this.serverAddress = serverAddress;
        log.info("serverAddress: {}", serverAddress);

        URL url;
        try {
            url = new URL(serverAddress);
        } catch (MalformedURLException e) {
            throw new RuntimeException(e);
        }
        protocol = url.getProtocol();
        host = url.getHost();
        port = url.getPort();
    }

    public SimpleRpcConnector(String protocol, String host, int port) {
        this.protocol = protocol;
        this.host = host;
        this.port = port;

        this.serverAddress = protocol == null ? "" : protocol + host + ":" + port;
        this.rpcProtocol = RpcProtocol.ProtocolRegistry.getRpcProtocol(protocol);
        log.info("serverAddress: {}", serverAddress);
    }

    @Override
    public RpcResponse send(RpcRequest rpcRequest) throws IOException {
        log.info("rpcRequest: {}", rpcRequest);

        Socket socket = new Socket(host, port);

        RpcResponse rpcResponse = new RpcResponse();
        OutputStream output = null;
        InputStream input = null;
        try {
            output = socket.getOutputStream();

            // 发送请求
            byte[] bytes = rpcProtocol.encode(rpcRequest);
            output.write(bytes);
            output.flush();
            // 同步阻塞等待服务器返回应答，获取应答后返回
            input = socket.getInputStream();
            rpcResponse = rpcProtocol.decode(input, RpcResponse.class);
        } catch (IOException e) {
            log.error(e.getMessage(), e);
            rpcResponse.setError(e.getMessage()).setRequestId(rpcRequest.getRequestId());
        } finally {
            IOUtils.close(output);
            IOUtils.close(input);
            IOUtils.close(socket);
        }

        log.info("rpcResponse: {}", rpcResponse);
        return rpcResponse;
    }

}
